const Console = console

const bsChalkColor = {
  black: '#000000',
  red: '#FF0000',
  green: '#008000',
  yellow: '#ffa930',
  blue: '#0000FF',
  magenta: '#FF00FF',
  cyan: '#00FFFF',
  white: '#FFFFFF',
} as const

const bsChalkMethod = {
  log: 'black',
  info: 'blue',
  warn: 'yellow',
  error: 'red',
  wait: 'cyan',
  ready: 'green',
  event: 'magenta',
  table: 'blue',
} as const

export type BsChalkColorKey = keyof typeof bsChalkColor;

export type BsChalkBgColorKey = `bg${Capitalize<BsChalkColorKey>}`;

export type BsChalkColorFn = (str: string | number | string[]) => string[];

export type BsChalkMethodKey = keyof typeof bsChalkMethod;

export type BsChalkColorFnMapType = Record<BsChalkColorKey, BsChalkColorFn> & Record<BsChalkBgColorKey, BsChalkColorFn> & {
  bold: BsChalkColorFn;
};

export type BsChalkOtherAddParam = string[][] | string[];

export type BsChalkMethodFn = (...str: BsChalkOtherAddParam) => void;

export type BsChalkMethodFnMap = Record<BsChalkMethodKey, BsChalkMethodFn>;

export type BsChalkOtherAdd = (...arr: BsChalkOtherAddParam) => string[];

export type BsChalk = BsChalkColorFnMapType & BsChalkMethodFnMap & {
  add: BsChalkOtherAdd;
  printBaseInfo: (title: string, version: string) => void;
};

let innerChalk: BsChalk = {} as any

/**
 * @description 工具类 - 生成基本数组， 供add使用
 * @example bsChalk.bold('123') => ['%c123', 'font-weight: bold']
 * @example bsChalk.bold(chalk.red('123')) => ['%c123', 'color: red; font-weight: bold']
 */
const BsChalkColorFnMap: BsChalkColorFnMapType = {
  bold: (str: string | number | string[]) => {
    if (typeof str === 'string' || typeof str === 'number') {
      return [`%c${str}`, 'font-weight: bold']
    }
    for (let key = 1; key < str.length; key += 1) {
      str[key] += '; font-weight: bold;'
    }
    return str
  },
} as any

/**
 * @description 处理数据
 * @param {BsChalkOtherAddParam} arr
 * @returns {string[]}
 * @example
 * add(['%c123', 'color: blue',], ['%c456', 'color: green']) => ["%c123%c456", "color: blue", "color: green"]
 * add('%c123') => ['%123']
 */
const add: BsChalkOtherAdd = (...arr) => {
  let fi = ['']
  for (let key = 0; key < arr.length; key += 1) {
    if (Array.isArray(arr[key])) {
      const [first, ...other] = arr[key]
      fi[0] += first
      fi = fi.concat(other)
    } else {
      fi[0] += arr[key]
    }
  }
  return fi
}

const firstToUpperCase = (str: string): string => str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase())

const createlog = (method: BsChalkMethodKey) => (...args: string[]) => {
  const fun = (Console as any)[method] ? (Console as any)[method] : Console.log
  fun(...args)
}

const createChalk = (method: BsChalkMethodKey) => (...str: BsChalkOtherAddParam) => {
  // example: str === [["%c336", "color: #F0F;font-weight: bold;"], ["%crty", "color: #F00;font-weight: bold;"]]
  if (Array.isArray(str[0])) {
    createlog(method)(
      ...add(
        BsChalkColorFnMap.bold(BsChalkColorFnMap[bsChalkMethod[method]](`[${firstToUpperCase(method)}] `)),
        ...str as string[][],
      ),
    )
    return
  }
  // example: str === ["%c336", "color: #FF0000;font-weight: bold;"]
  createlog(method)(
    ...add(
      BsChalkColorFnMap.bold(BsChalkColorFnMap[bsChalkMethod[method]](`[${firstToUpperCase(method)}] `)),
      str as string[],
    ),
  )
}

/**
 * @description 生成基本数据，供add使用
 */
Object.keys(bsChalkColor).forEach((color) => {
  const colorKey = color as BsChalkColorKey
  BsChalkColorFnMap[colorKey] = (str: string | number | string[]) => {
    // bsChalk.red('123') => ['%c123', 'color: red']
    if (typeof str === 'string' || typeof str === 'number') {
      return [`%c${str}`, `color: ${bsChalkColor[colorKey]}`]
    }
    // bsChalk.red(bsChalk.bold('123')) => ['%c123', 'font-weight: bold; color: red']
    for (let i = 1; i < str.length; i += 1) {
      str[i] += `; color:${bsChalkColor[colorKey]}`
    }
    return str
  }
  // 添加背景色设置
  const bgKey = `bg${firstToUpperCase(color)}` as BsChalkBgColorKey;
  BsChalkColorFnMap[bgKey] = (str: string | number | string[]) => {
    // bsChalk.bgRed('123') => ['%c123', 'padding: 2px 4px; border-radius: 3px; color: xxx; font-weight: bold; background: red']
    if (typeof str === 'string' || typeof str === 'number') {
      return [
        `%c${str}`,
        `padding: 2px 4px; border-radius: 3px; color: ${color === 'white' ? '#000' : '#fff'
        }; font-weight: bold; background: ${bsChalkColor[colorKey]};`,
      ]
    }
    // bsChalk.bgRed(bsChalk.blue('123')) => ['%c123', 'color: blue; padding: 2px 4px; border-radius: 3px; font-weight: bold; background: red']
    for (let i = 1; i < str.length; i += 1) {
      str[i] += `; padding: 2px 4px; border-radius: 3px; font-weight: bold; background: ${bsChalkColor[colorKey]};`
    }
    return str
  }
})

// const handerField = function <T extends object, K extends keyof T>(obj: T, key: K) {
//   return obj[key]
// }

Object.keys(bsChalkMethod).forEach((method) => {
  innerChalk[method as BsChalkMethodKey] = createChalk(method as BsChalkMethodKey)
})

const printBaseInfo = (title: string, version: string): void => createlog('log')(
  `%c ${title} %c V${version} `,
  'padding: 2px 0px; border-radius: 3px 0 0 3px; color: #fff; background: #606060; font-weight: bold;',
  'padding: 2px 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e; font-weight: bold;',
)

innerChalk = {
  ...innerChalk,
  ...BsChalkColorFnMap,
  add,
  printBaseInfo,
}

export const bsChalk = innerChalk
